﻿//
//                       _oo0oo_
//                      o8888888o
//                      88" . "88
//                      (| -_- |)
//                      0\  =  /0
//                    ___/`---'\___
//                  .' \\|     |// '.
//                 / \\|||  :  |||// \
//                / _||||| -:- |||||- \
//               |   | \\\  -  /// |   |
//               | \_|  ''\---/''  |_/ |
//               \  .-\__  '-'  ___/-. /
//             ___'. .'  /--.--\  `. .'___
//          ."" '<  `.___\_<|>_/___.' >' "".
//         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//         \  \ `_.   \_ __\ /__ _/   .-` /  /
//     =====`-.____`.___ \_____/___.-`___.-'=====
//                       `=---='
//
//
//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//               佛祖保佑         永无BUG
//
//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#region << 版 本 注 释 >>

/*----------------------------------------------------------------
* 类 名 称 ：GameObjectExtensions
* 类 描 述 ：
* 作    者 ：henrychang
* 创建时间 ：2019/1/5 15:35:29
*******************************************************************
* Copyright @ henrychang 2018. All rights reserved.
*******************************************************************
//----------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

using System;
using System.Linq;
using UnityEngine;

/// <summary>
/// GameObject的扩展方法
/// </summary>
public static class GameObjectExtensions
{
    /// <summary>
    /// 返回所有接口类型的MonoBehaviors（强制转换为T）
    /// </summary>
    /// <typeparam name="T">接口类型</typeparam>
    /// <param name="gObj"></param>
    /// <returns></returns>
    public static T[] GetInterfaces<T>(this GameObject gObj)
    {
        var mObjs = gObj.GetComponents<MonoBehaviour>();

        return (from a in mObjs where a.GetType().GetInterfaces().Any(k => k == typeof(T)) select (T)(object)a).ToArray();
    }

    /// <summary>
    /// 返回接口类型的第一个MonoBehavior（强制转换为T）
    /// </summary>
    /// <typeparam name="T">接口类型</typeparam>
    /// <param name="gObj"></param>
    /// <returns></returns>
    public static T GetInterface<T>(this GameObject gObj)
    {
        return gObj.GetInterfaces<T>().FirstOrDefault();
    }

    /// <summary>
    /// 返回接口类型t（强制转换为t）的MonoBehavior的第一个实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="gObj"></param>
    /// <returns></returns>
    public static T GetInterfaceInChildren<T>(this GameObject gObj)
    {
        return gObj.GetInterfacesInChildren<T>().FirstOrDefault();
    }

    /// <summary>
    /// 获取实现类型t（强制转换为t）的接口的子级中的所有的MonoBehavior
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="gObj"></param>
    /// <returns></returns>
    public static T[] GetInterfacesInChildren<T>(this GameObject gObj)
    {
        var mObjs = gObj.GetComponentsInChildren<MonoBehaviour>();

        return (from a in mObjs where a.GetType().GetInterfaces().Any(k => k == typeof(T)) select (T)(object)a).ToArray();
    }

    /// <summary>
    /// 销毁所有的child
    /// </summary>
    public static void DestroyChildren(this GameObject gObj)
    {
        for (int i = gObj.transform.childCount - 1; i >= 0; --i)
        {
            UnityEngine.Object.Destroy(gObj.transform.GetChild(i).gameObject);
        }
        gObj.transform.DetachChildren();
    }

    /// <summary>
    /// 通过迭代父项获取GameObject的路径
    /// </summary>
    /// <param name="current"></param>
    /// <returns></returns>
    public static string GetPath(this GameObject current)
    {
        if (current.transform.parent == null)
            return "/" + current.name;
        return current.transform.parent.gameObject.GetPath() + "/" + current.name;
    }

    #region Show

    public static GameObject Show(this GameObject selfObj)
    {
        selfObj.SetActive(true);
        return selfObj;
    }

    public static T Show<T>(this T selfComponent) where T : Component
    {
        selfComponent.gameObject.Show();
        return selfComponent;
    }

    #endregion Show

    #region Hide

    public static GameObject Hide(this GameObject selfObj)
    {
        selfObj.SetActive(false);
        return selfObj;
    }

    public static T Hide<T>(this T selfComponent) where T : Component
    {
        selfComponent.gameObject.Hide();
        return selfComponent;
    }

    #endregion Hide

    #region DestroyGameObj

    public static void DestroyGameObj<T>(this T selfBehaviour) where T : Component
    {
        selfBehaviour.gameObject.DestroySelf();
    }

    #endregion DestroyGameObj

    #region DestroyGameObjGracefully

    public static void DestroyGameObjGracefully<T>(this T selfBehaviour) where T : Component
    {
        if (selfBehaviour && selfBehaviour.gameObject)
        {
            selfBehaviour.gameObject.DestroySelfGracefully();
        }
    }

    #endregion DestroyGameObjGracefully

    #region DestroyGameObjGracefully

    public static T DestroyGameObjAfterDelay<T>(this T selfBehaviour, float delay) where T : Component
    {
        selfBehaviour.gameObject.DestroySelfAfterDelay(delay);
        return selfBehaviour;
    }

    public static T DestroyGameObjAfterDelayGracefully<T>(this T selfBehaviour, float delay) where T : Component
    {
        if (selfBehaviour && selfBehaviour.gameObject)
        {
            selfBehaviour.gameObject.DestroySelfAfterDelay(delay);
        }

        return selfBehaviour;
    }

    #endregion DestroyGameObjGracefully

    #region Layer

    public static GameObject Layer(this GameObject selfObj, int layer)
    {
        selfObj.layer = layer;
        return selfObj;
    }

    public static T Layer<T>(this T selfComponent, int layer) where T : Component
    {
        selfComponent.gameObject.layer = layer;
        return selfComponent;
    }

    public static GameObject Layer(this GameObject selfObj, string layerName)
    {
        selfObj.layer = LayerMask.NameToLayer(layerName);
        return selfObj;
    }

    public static T Layer<T>(this T selfComponent, string layerName) where T : Component
    {
        selfComponent.gameObject.layer = LayerMask.NameToLayer(layerName);
        return selfComponent;
    }

    #endregion Layer

    #region Component

    public static T GetOrAddComponent<T>(this GameObject selfComponent) where T : Component
    {
        var comp = selfComponent.gameObject.GetComponent<T>();
        return comp ? comp : selfComponent.gameObject.AddComponent<T>();
    }

    public static Component GetOrAddComponent(this GameObject selfComponent, Type type)
    {
        var comp = selfComponent.gameObject.GetComponent(type);
        return comp ? comp : selfComponent.gameObject.AddComponent(type);
    }

    #endregion Component
}